#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <limits.h>
#include <fcntl.h>
#include <time.h>
#include <utime.h>
#include <getch.h>
#include <signal.h>
#include "tools.h"
#include "network.h"
#include "ftp_client.h"

struct FTPClient
{
	NetWork* cnw;
	NetWork* pnw;
	int fd;
	char ip[16];
	char buf[4096];
	char path[PATH_MAX];
	char file[PATH_MAX];
	char smdtm[15];
	char cmdtm[15];
	bool is_put;
	bool is_get;
}* ftp;

// 获取文件的最后修改时间
int get_file_mdtm(const char* file,char* mdtm)
{
	struct stat buf;
	if(stat(file,&buf))
		return -1;

	struct tm* tm = localtime(&buf.st_mtim.tv_sec);
	if(NULL == tm)
		return -1;
	
	sprintf(mdtm,"%04d%02d%02d%02d%02d%02d",
		tm->tm_year+1900,
		tm->tm_mon+1,
		tm->tm_mday,
		tm->tm_hour,
		tm->tm_min,
		tm->tm_sec);

	return 0;
}

// 设置文件的最后修改时间
int set_file_mdtm(const char* file,const char* mdtm)
{
	struct tm tm;
	sscanf(mdtm,"%4d%2d%2d%2d%2d%2d",
		&tm.tm_year,
		&tm.tm_mon,
		&tm.tm_mday,
		&tm.tm_hour,
		&tm.tm_min,
		&tm.tm_sec);
	tm.tm_year -= 1900;
	tm.tm_mon -= 1;
	struct utimbuf utimbuf;
	utimbuf.modtime = mktime(&tm);
	return utime(file,&utimbuf);
}

bool check_status(int status)
{
	int ret = recv_nw(ftp->cnw,ftp->buf,sizeof(ftp->buf));
	if(0 >= ret)
	{
		puts("服务器连接已断开，请重新登陆");
		exit(-1);
	}

	ftp->buf[ret] = '\0';
	printf("recv:%s",ftp->buf);
	return atoi(ftp->buf) == status;
}

bool send_cmd(int status)
{
	int ret = send_nw(ftp->cnw,ftp->buf,strlen(ftp->buf));
	if(0 >= ret)
	{
		puts("服务器连接已断开，请重新登陆");
		exit(-1);
	}
	printf("send:%s",ftp->buf);
	return check_status(status);
}

void read_and_write(int src_fd,int dest_fd)
{
	uint8_t tmp[255],ret;
	while(ret = read(src_fd,tmp,sizeof(tmp)))
	{
		write(dest_fd,tmp,ret);
		sleep(1);
	}
}

void pasv_ftp_client(void)
{
	sprintf(ftp->buf,"PASV\n");
	if(!send_cmd(227))
	{
		puts("该服务不支持PASV模式，请联系作者!");
		exit(0);
	}

	uint8_t ip1,ip2,ip3,ip4,port1,port2;
	sscanf(strchr(ftp->buf,'(')+1,"%hhu,%hhu,%hhu,%hhu,%hhu,%hhu",
		&ip1,&ip2,&ip3,&ip4,&port1,&port2);

	ftp->pnw = open_nw(SOCK_STREAM,port1*256+port2,ftp->ip,false);
	if(NULL == ftp->pnw)
	{
		printf("无法连接FTP服务器:%s\n",ftp->ip);
		exit(-1);
	}
}

void login_ftp_client(const char* ip,uint16_t port)
{
	ftp = malloc(sizeof(struct FTPClient));
	ftp->cnw = open_nw(SOCK_STREAM,port,ip,false);
	if(NULL == ftp->cnw)
	{
		printf("无法连接FTP服务器:%s\n",ip);
		exit(-1);
	}
	
	// 备份ip地址
	strcpy(ftp->ip,ip);
	
	// 检查连接结果
	check_status(220);
	
	char user[256];
	printf("请输入用户名：");
	scanf("%s",user);
	sprintf(ftp->buf,"USER %s\n",user);
	if(!send_cmd(331))
	{
		puts("输入的用户名用误！");
		exit(0);
	}
	
	char pass[256];
	printf("请输入用户名：");
	get_passwd(pass,sizeof(pass),false);
	sprintf(ftp->buf,"PASS %s\n",pass);
	if(!send_cmd(230))
	{
		puts("用户名或密码错误!");
		exit(0);
	}
	
	pwd_ftp_client();
}
void pwd_ftp_client(void)
{
	printf("%s %s\n",__FILE__,__func__);
	sprintf(ftp->buf,"PWD\n");
	if(send_cmd(257))
	{
		sscanf(ftp->buf,"257 \"%s",ftp->path);
		ftp->path[strlen(ftp->path)-1] = '\0';
		printf("path:%s\n",ftp->path);
	}
}
void cd_ftp_client(void)
{
	printf("%s %s\n",__FILE__,__func__);
	char dir[PATH_MAX];
	scanf("%s",dir);
	sprintf(ftp->buf,"CWD %s\n",dir);
	send_cmd(250);
	pwd_ftp_client();
}
void mkdir_ftp_client(void)
{
	printf("%s %s\n",__FILE__,__func__);
	char dir[PATH_MAX];
	scanf("%s",dir);
	sprintf(ftp->buf,"MKD %s\n",dir);
	send_cmd(257);
}
void rmdir_ftp_client(void)
{
	printf("%s %s\n",__FILE__,__func__);
	char dir[PATH_MAX];
	scanf("%s",dir);
	sprintf(ftp->buf,"RMD %s\n",dir);
	send_cmd(257);
}
void ls_ftp_client(void)
{
	printf("%s %s\n",__FILE__,__func__);
	pasv_ftp_client();
	sprintf(ftp->buf,"LIST -al\n");
	send_cmd(150);
	read_and_write(ftp->pnw->sockfd,1);
	if(check_status(226))
	{
		close_nw(ftp->pnw);
	}
}
void put_ftp_client(void)
{
	printf("%s %s\n",__FILE__,__func__);
	
	// 备份文件名
	scanf("%s",ftp->file);
	// 如果本地文件不存在则结束
	ftp->fd = open(ftp->file,O_RDONLY);
	if(0 > ftp->fd)
	{
		printf("%s 文件不存在，请检查文件名!\n",ftp->file);
		return;
	}
	
	// SIZE file
	sprintf(ftp->buf,"SIZE %s\n",ftp->file);
	
	// 获取本地文件的最后修改时间
	get_file_mdtm(ftp->file,ftp->cmdtm);

	// 检查服务端是否有同名文件
	if(send_cmd(213))
	{
		// 读取服务端文件的字节数
		size_t sfile_size;
		sscanf(ftp->buf+4,"%u",&sfile_size);

		// 获取服务端文件的最后修改时间
		sprintf(ftp->buf,"MDTM %s\n",ftp->file);
		send_cmd(213);
		sscanf(ftp->buf+4,"%s",ftp->smdtm);

		if(!strcmp(ftp->smdtm,ftp->cmdtm))
		{
			size_t cfile_size = file_size(ftp->file);
			if(sfile_size == cfile_size)
			{
				printf("已经上传完成!\n");
				close(ftp->fd);
				return;
			}

			// 开始续传
			sprintf(ftp->buf,"REST %u\n",sfile_size);
			send_cmd(350);
			lseek(ftp->fd,sfile_size,SEEK_SET);
			printf("---------------------\n");
		}
		else
		{
			printf("已有同名文件，是否覆盖?(y/n)");
			if('y' != getch())
			{
				close(ftp->fd);
				return;
			}
		}
	}	

	// 正常上传，服务器会自动覆盖。
	pasv_ftp_client();
	sprintf(ftp->buf,"STOR %s\n",ftp->file);
	send_cmd(150);
	ftp->is_put = true;
	read_and_write(ftp->fd,ftp->pnw->sockfd);
	close_nw(ftp->pnw);
	close(ftp->fd);
	check_status(226);

	sprintf(ftp->buf,"MDTM %s %s/%s\n",ftp->cmdtm,ftp->path,ftp->file);
	send_cmd(213);
	ftp->is_put = false;
}

void get_ftp_client(void)
{
	printf("%s %s\n",__FILE__,__func__);
	scanf("%s",ftp->file);
	
	sprintf(ftp->buf,"SIZE %s\n",ftp->file);
	if(!send_cmd(213))
	{
		printf("%s 文件不存在，请检查文件名!\n",ftp->file);
		return;
	}
	
	// 提取文件的字节数
	size_t sfile_size;
	sscanf(ftp->buf+4,"%u",&sfile_size);
	
	// 检查本地位置文件是否已经
	ftp->fd = open(ftp->file,O_WRONLY);
	printf("------------%d\n",ftp->fd);
	if(0 < ftp->fd)
	{// 断点续传或覆盖
	
		// 服务端文件的最后修改时间
		sprintf(ftp->buf,"MDTM %s\n",ftp->file);
		send_cmd(213);
		sscanf(ftp->buf+4,"%s",ftp->smdtm);
		
		// 本地文件的最后修改时间
		get_file_mdtm(ftp->file,ftp->cmdtm);
		
		// 获取本地文件的字节数
		size_t cfile_size = file_size(ftp->file);
		
		printf("%s %s\n",ftp->smdtm,ftp->cmdtm);
		if(!strcmp(ftp->smdtm,ftp->cmdtm))
		{
			printf("%u %u\n",cfile_size , sfile_size);
			if(cfile_size == sfile_size)
			{
				printf("已经下载完成!\n");
				close(ftp->fd);
				return;
			}
			else if(cfile_size < sfile_size)
			{
				sprintf(ftp->buf,"TYPE I\n");
				send_cmd(200);
				
				printf("断点续传已经实现!\n");
				// REST 本地文件的的字节数
				sprintf(ftp->buf,"REST %u\n",cfile_size);
				send_cmd(350);
				
				// 文件的位置指针调整到末尾
				lseek(ftp->fd,0,SEEK_END);
			}
		}
		else
		{
			printf("已有同名文件，是否覆盖?(y/n)");
			if('y' != getch())
			{
				close(ftp->fd);
				return;
			}
			ftruncate(ftp->fd,0);
		}
	}
	else
	{
		ftp->fd = open(ftp->file,O_WRONLY|O_CREAT,0644);
		if(0 > ftp->fd)
		{
			puts("当前目录没有写权限，下载文件失败!");
			return;
		}
		
		// 服务端文件的最后修改时间
		sprintf(ftp->buf,"MDTM %s\n",ftp->file);
		send_cmd(213);
		sscanf(ftp->buf+4,"%s",ftp->smdtm);
	}
	
	// 开启pasv模式
	// 正常上传，服务器会自动覆盖。
	pasv_ftp_client();
	sprintf(ftp->buf,"RETR %s\n",ftp->file);
	send_cmd(150);
	ftp->is_get = true;
	read_and_write(ftp->pnw->sockfd,ftp->fd);
	close_nw(ftp->pnw);
	close(ftp->fd);
	check_status(226);

	printf("smdtm%s\n",ftp->smdtm);
	set_file_mdtm(ftp->file,ftp->smdtm);
	ftp->is_put = false;
}
void rm_ftp_client(void)
{
	printf("%s %s\n",__FILE__,__func__);
	char file[PATH_MAX];
	scanf("%s",file);
	sprintf(ftp->buf,"DELE %s\n",file);
	send_cmd(257);
}

void bye_ftp_client(void)
{
	printf("%s %s\n",__FILE__,__func__);
	sprintf(ftp->buf,"QUIT\n");
	send_cmd(221);
	exit(0);
}

void sigint(int signum)
{
	if(ftp->is_put)
	{
		close_nw(ftp->pnw);
		close(ftp->fd);
		sprintf(ftp->buf,"MDTM %s %s/%s\n",ftp->cmdtm,ftp->path,ftp->file);
		send_cmd(213);
	}
	if(ftp->is_get)
	{
		close_nw(ftp->pnw);
		close(ftp->fd);
		set_file_mdtm(ftp->file,ftp->smdtm);
	}
	exit(-1);
}
